<!DOCTYPE html>
<html lang="">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">

    
      <link rel="icon" href="/favicon.png" />
    

    <title>
        
          CODE&#39;NOTE
        
    </title>

    <!-- Spectre.css framework -->
    <link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/spectre.css/0.5.9/spectre.min.css" rel="stylesheet">
    <link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/spectre.css/0.5.9/spectre-exp.min.css" rel="stylesheet">
    <link href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/spectre.css/0.5.9/spectre-icons.min.css" rel="stylesheet">

    <!-- theme css & js -->
    
<link rel="stylesheet" href="/css/book.css">

    
<script src="/js/book.js"></script>


    <!-- tocbot -->
    <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/tocbot/4.18.2/tocbot.min.js"></script>
    <link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/tocbot/4.18.2/tocbot.css" rel="stylesheet">
    
    <!-- katex -->    
    <link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/KaTeX/0.15.2/katex.min.css" rel="stylesheet">

    
    
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/zooming/2.1.1/zooming.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
    const zooming = new Zooming()
    zooming.listen('.book-content img')
})
</script>

<meta name="generator" content="Hexo 6.1.0"></head>

<body>

<div class="book-container">
  <div class="book-sidebar">
    <div class="book-brand">
  <a href="/">
    <img src="/favicon.png">
    <span>CODE&#39;NOTE</span>
  </a>
</div>
    <div id="menu" class="book-menu hide">
  <h2 id="☘️-Home">☘️ <a href="/">Home</a></h2>
<h2 id="Go">Go</h2>
<ul>
<li><a href="/go/01%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA">0.1 开发环境搭建</a></li>
<li><a href="/go/02%E5%8F%98%E9%87%8F%E5%92%8C%E5%B8%B8%E9%87%8F">0.2 变量和常量</a></li>
<li><a href="/go/03%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B">0.3 基本数据类型</a></li>
<li><a href="/go/04%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%92%8C%E8%BF%90%E7%AE%97%E7%AC%A6">0.4 流程控制和运算符</a></li>
<li><a href="/go/05%E6%95%B0%E7%BB%84">0.5 数组</a></li>
<li><a href="/go/06%E5%88%87%E7%89%87">0.6 切片</a></li>
<li><a href="/go/07map">0.7 map</a></li>
<li><a href="/go/08%E5%87%BD%E6%95%B0">0.8 函数</a></li>
<li><a href="/go/09%E6%8C%87%E9%92%88">0.9 指针</a></li>
<li><a href="/go/10%E5%8F%8D%E5%B0%84">1.0 反射</a></li>
<li><a href="/go/11%E7%BB%93%E6%9E%84%E4%BD%93">1.1 结构体</a></li>
<li><a href="/go/12%E6%8E%A5%E5%8F%A3">1.2 接口</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine">1.3 goroutine</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/channel">1.4 channel</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%89%E5%85%A8%E5%92%8C%E9%94%81">1.5 并发安全和锁</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C">1.6 原子操作</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/GPM%E5%8E%9F%E7%90%86%E4%B8%8E%E8%B0%83%E5%BA%A6">1.7 GPM与调度分析</a></li>
<li><a href="/go/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/CSP%E5%B9%B6%E5%8F%91%E6%A8%A1%E5%9E%8B">1.8 CSP并发模型</a></li>
<li><a href="/go/%E6%A0%87%E5%87%86%E5%BA%93/fmt">标准库fmt</a></li>
<li><a href="/go/%E6%A0%87%E5%87%86%E5%BA%93/flag">标准库flag</a></li>
<li><a href="/go/%E6%A0%87%E5%87%86%E5%BA%93/time">标准库time</a></li>
<li><a href="/go/%E6%A0%87%E5%87%86%E5%BA%93/go_%E6%A0%87%E5%87%86%E5%BA%93log">标准库log</a></li>
</ul>
<!-- ##
## .NET

* [C# 入门基础合集](/dotnet/基础合集)
* [C# 面向对象](/dotnet/面向对象)
* [C# 数据结构](/dotnet/数据结构)
* [C# 泛型技术](/dotnet/泛型技术)
* [C# 反射技术](/dotnet/反射技术)
* [C# 多线程开发](/dotnet/多线程开发)
* [C# 多线程之线程同步技术](/dotnet/多线程之线程同步技术)
* [C# 委托和事件详解](/dotnet/委托和事件详解)
* [C# 并行编程](/dotnet/并行编程)
* [C# 异步编程](/dotnet/异步编程)
* [C# 值类型和引用类型内存分配](/dotnet/值类型和引用类型的内存分配)
* [1.1 DataProtection简介](/dotnet/1.1DataProtection简介)
* [1.2 DataProtection方法介绍](/dotnet/1.2DataProtection方法介绍)
* [1.3 落地实践及多环境调试](/dotnet/1.3落地实践及多环境调试)
* [1.4 UserSecrets](/dotnet/1.4UserSecrets)
* [1.5 数据保护方案](/dotnet/1.5基于DataProtection的数据保护方案)
* [1.6 集成AzureDevops](/dotnet/1.6方案实践及集成AzureDevops管道)


ELK Stack

* [ElastaticSearch入门](/elk/1.1ElastaticSearch入门)
* [ElastaticSearch配置](/elk/1.2ElastaticSearch配置)
* [使用Kibana操作ES](/elk/1.3使用Kibana操作ES)
 ## Docker

* [1.1 Docker概念及安装](/docker/1.1Docker概念及安装)
* [1.2 Docker镜像](/docker/1.2Docker镜像)
* [1.3 Docker容器](/docker/1.3Docker容器)
* [1.4 Docker仓库](/docker/1.4Docker仓库)
* [1.5 Docker数据管理](/docker/1.5Docker数据管理)
* [1.6 Docker容器四种网络模式](/docker/1.6Docker容器四种网络模式)
* [1.7 Docker高级网络配置](/docker/1.7Docker高级网络配置)
* [1.8 Dockerfile](/docker/1.8Dockerfile)
* [1.9 DockerCompose](/docker/1.9Docker三剑客之DockerCompose)
* [2.0 DockerMachine](/docker/2.0Docker三剑客之DockerMachine)
* [2.1 DockerSwarm](/docker/2.1Docker三剑客之DockerSwarm)
* [2.2 Docker常用命令](/docker/2.2Docker常用命令)
* [Portainer可视化面板](/docker/Portainer可视化面板)
* [1.6 Docker四种网络模式](/docker/1.6Docker容器网络模式)
* [1.7 Docker高级网络配置](/docker/1.7Docker高级网络配置)
* [1.8 Dockerfile](/docker/1.8Dockerfile)
* [1.9 DockerCompose](/docker/1.9DockerCompose)
* [2.0 DockerMachine](/docker/2.0DockerMachine)
* [2.1 DockerSwarm](/docker/2.1DockerSwarm)
* [2.2 Docker常用命令](/docker/2.2Docker常用命令)
* [Portainer可视化面板](/docker/Portainer可视化面板) 

## Linux

* [Centos安装](/linux/Centos安装)
* [Linux目录说明](/linux/Linux目录说明)
* [Centos网络配置](/linux/Centos网络配置)
* [Centos7升级gcc版本](/linux/Centos7升级gcc版本)
* [Linux常用命令](/linux/Linux常用命令)

## RabbitMQ

* [1.1 RabbitMQ概念及安装](/rabbitMq/1.1RabbitMQ概念及安装)
* [1.2 工作模式介绍](/rabbitMq/1.2工作模式介绍)
* [1.3 消息确认及持久化](/rabbitMq/1.3消息确认及持久化)
* [1.4 两种消费模式和QOS](/rabbitMq/1.4两种消费模式和QOS的实现)
* [1.5 Channel常见方法](/rabbitMq/1.5Channel常见方法)
* [1.6 RabbitMQ常用命令](/rabbitMq/1.6RabbitMQ常用命令)
* [1.7 RabbitMQ常见策略](/rabbitMq/1.7RabbitMQ常见策略)
* [1.8 RabbitMQ常见问题](/rabbitMq/1.8RabbitMQ常见问题)
* [1.9 RabbitMQ集群方案](/rabbitMq/1.9RabbitMQ集群方案)
* [客户端连接RabbitMQ](/rabbitMq/客户端连接RabbitMQ)

## Redis

* [1.1 NoSql概述](/redis/1.1NoSql概述)
* [1.2 Redis安装](/redis/1.2Redis安装)
* [1.3 Redis基本数据类型](/redis/1.3Redis基本数据类型)
* [1.4 Redis特殊数据类型](/redis/1.4Redis特殊数据类型)
* [1.5 Redis事务操作](/redis/1.5Redis事务操作)
* [1.6 Redis配置文件详解](/redis/1.6Redis配置文件详解)
* [1.7 Redis持久化](/redis/1.7Redis持久化)
* [1.8 Redis发布订阅](/redis/1.8Redis发布订阅)
* [1.9 Redis集群方案](/redis/1.9Redis集群方案)
* [1.10 Redis常见问题](/redis/1.10Redis常见问题)
* [客户端连接Redis](/redis/客户端连接Redis)
* [使用Docker搭建Redis集群](/redis/使用Docker搭建Redis集群)

## MicroService

* [1.1 微服务之项目搭建](/microservice/1.1微服务入门之项目搭建)
* [1.2 微服务之服务注册发现](/microservice/1.2微服务入门之服务注册与发现)
* [1.3 微服务之网关](/microservice/1.3微服务入门之网关)
* [1.4 微服务之事件总线](/microservice/1.4微服务入门之事件总线)
* [1.5 微服务之DockerCompose](/microservice/1.5微服务入门之DockerCompose)
* [Consul服务注册发现](/microservice/Consul服务注册发现)

## Test

* [单元测试](/test/单元测试)
* [集成测试](/test/集成测试)
* [压力测试k6](/test/压力测试k6)
* [自动化UI测试](/test/自动化UI测试) -->

</div>


<script src="/js/book-menu.js"></script>

  </div>

  <div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
  <div class="sidebar-toggle-inner"></div>
</div>

<script>
function add_inner() {
  let inner = document.querySelector('.sidebar-toggle-inner')
  inner.classList.add('show')  
}

function remove_inner() {
  let inner = document.querySelector('.sidebar-toggle-inner')
  inner.classList.remove('show')
}

function sidebar_toggle() {
    let sidebar_toggle = document.querySelector('.sidebar-toggle')
    let sidebar = document.querySelector('.book-sidebar')
    let content = document.querySelector('.off-canvas-content')
    if (sidebar_toggle.classList.contains('extend')) { // show
        sidebar_toggle.classList.remove('extend')
        sidebar.classList.remove('hide')
        content.classList.remove('extend')
    }
    else { // hide
        sidebar_toggle.classList.add('extend')
        sidebar.classList.add('hide')
        content.classList.add('extend')
    }
}
</script>

  <div class="off-canvas-content">
    <div class="columns">
      <div class="column col-10 col-lg-12">
        <div class="book-navbar">
          <!-- For Responsive Layout -->

<header class="navbar">
  <section class="navbar-section">
    <a onclick="open_sidebar()">
      <i class="icon icon-menu"></i>
    </a>
  </section>
</header>

        </div>
        <div class="book-content">
          <div class="book-post">
  <p>变量和常量是编程中必不可少的部分，也是比较好理解的一部分。</p>
<h1 id="标识符">标识符</h1>
<p>编程语言中标识符指：由程序员定义的具有特殊意义的词，比如变量名、常量名、函数名等。 Go语言中标识符由字母数字和<code>_</code>(下划线）组成，并且只能以字母和<code>_</code>开头且区分大小写。 比如：<code>abc</code>, <code>_123</code>, <code>a123</code>。</p>
<h1 id="关键字">关键字</h1>
<p>关键字指：编程语言中预先定义好的具有特殊含义的标识符。 关键字和保留字都不建议用作变量名。Go 语言中类似 C# 的关键字有25个，只能在特定语法结构中使用：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">break      default        func     interface    select</span><br><span class="line">case       defer          go       map          struct</span><br><span class="line">chan       else           goto     package      switch</span><br><span class="line">const      fallthrough    if       range        type</span><br><span class="line">continue   for            import   return       var</span><br></pre></td></tr></table></figure>
<p>除此之外Go语言中还有30多个预定义的名字，比如 int 和 ture 等，主要对应内建的常量、类型和函数：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">内建常量: true false iota nil</span><br><span class="line">内建类型: int   int8   int16   int32  int64   uint   uint8  uint16   uint32   uint64   uintptr  </span><br><span class="line">         float32   float64   complex128   complex64   bool   byte    rune   string  error</span><br><span class="line">内建函数: make  len  cap   new   append   copy   close   delete   complex   real    imag    panic  recover</span><br></pre></td></tr></table></figure>
<p>通常在 Go 语言编程中推荐的命名方式是驼峰命名。如：ReadAll，不推荐下划线命名。</p>
<h1 id="变量">变量</h1>
<h2 id="变量声明">变量声明</h2>
<p>变量声明语法如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> 变量名字 类型 = 表达式</span><br></pre></td></tr></table></figure>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 指定变量类型但不赋值，使用默认值</span></span><br><span class="line"><span class="keyword">var</span> v1 <span class="type">int</span>      <span class="comment">// 省略表达式，使用数值类型对应的零值初始化（0）</span></span><br><span class="line"><span class="keyword">var</span> v2 <span class="type">string</span>   <span class="comment">// 省略表达式，使用字符串对应的零值初始化（空字符串）</span></span><br><span class="line"><span class="keyword">var</span> v3 [<span class="number">10</span>]<span class="type">int</span>  <span class="comment">// 会创建长度为10的数据</span></span><br><span class="line"><span class="keyword">var</span> v4 []<span class="type">int</span>    <span class="comment">// 数组切片</span></span><br><span class="line"><span class="keyword">var</span> v5 <span class="keyword">struct</span> &#123; <span class="comment">// &#123;0&#125;</span></span><br><span class="line">	f <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> v6 *<span class="type">int</span>            <span class="comment">// 指针,因未被初始化所以默认值为nil</span></span><br><span class="line"><span class="keyword">var</span> v7 <span class="keyword">map</span>[<span class="type">string</span>]<span class="type">int</span>  <span class="comment">// map,key为string类型，value为int类型,默认值为map[]</span></span><br><span class="line"><span class="keyword">var</span> v8 <span class="function"><span class="keyword">func</span><span class="params">(a <span class="type">int</span>)</span></span> <span class="type">int</span> <span class="comment">// 函数类型,因未被初始化所以默认值为nil,直接调用会抛出空指针异常</span></span><br><span class="line">fmt.Println(v1, v2, v3, v4, v5, v6, v7, v8)</span><br></pre></td></tr></table></figure>
<p><strong>注意</strong>：</p>
<ol>
<li>Go 语言中变量声明采用<strong>类型后置</strong>方式，需要先声明变量名称再声明变量类型</li>
<li>语句最后不需要加<code>;</code>（如果需要一行写多条语句需要，但不推荐这么干）</li>
<li>如果定义的是局部变量，则必须使用，否则编译报错</li>
</ol>
<h2 id="批量声明">批量声明</h2>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 多变量声明使用此方式避免重复写var</span></span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">	v1 <span class="type">int</span></span><br><span class="line">	v2 <span class="type">string</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<p>或者这样：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> n1, n2, n3 <span class="type">string</span></span><br><span class="line">n1, n2, n3 = <span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span></span><br></pre></td></tr></table></figure>
<p>再或者这样：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> n4, n5, n6 = <span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span></span><br></pre></td></tr></table></figure>
<h2 id="变量初始化">变量初始化</h2>
<p>通常情况下 <code>类型 </code>或 <code>= 表达式</code> 两个部分可以省略其中的一个。如果省略的是类型信息，将根据初始化表达式来推导变量的类型信息。如果初始化表达式被省略，那么将用零值初始化该变量。</p>
<ul>
<li>数值类型变量对应的零值是 <code>0</code></li>
<li>布尔类型变量对应的零值是 <code>false</code></li>
<li>字符串类型对应的零值是 <code>空字符串</code></li>
<li>接口或引用类型（包括slice、map、chan和函数）变量对应的零值是 <code>nil</code></li>
<li>数组或结构体等聚合类型对应的零值是每个元素或字段对应类型的零值</li>
</ul>
<p>零值初始化机制可以确保每个声明的变量总是有一个良好定义的值，以保证不存在未初始化的变量。</p>
<h3 id="1：指定类型但不赋值">1：指定类型但不赋值</h3>
<p>指定类型但不赋值，将使用类型的默认零值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name <span class="type">string</span> <span class="comment">// 省略表达式，使用字符串对应的零值初始化（空字符串）</span></span><br><span class="line"><span class="keyword">var</span> age <span class="type">int</span>     <span class="comment">// 省略表达式，使用数值类型对应的零值初始化（0）</span></span><br><span class="line">fmt.Println(name, age)</span><br></pre></td></tr></table></figure>
<h3 id="2：使用类型推断">2：使用类型推断</h3>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> address = <span class="string">&quot;beijing&quot;</span></span><br><span class="line">fmt.Println(address)</span><br></pre></td></tr></table></figure>
<h3 id="3：简短声明">3：简短声明</h3>
<p>简短声明，以<code>名字 := 表达式 </code>形式声明变量，变量的类型根据表达式来自动推导。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sex := <span class="string">&quot;男&quot;</span></span><br><span class="line">fmt.Println(sex)</span><br></pre></td></tr></table></figure>
<h3 id="4：使用-new-函数">4：使用 new 函数</h3>
<p>调用内建的 <code>new</code> 函数创建变量。表达式 <code>new(T)</code>将创建一个 <code>T</code> 类型的匿名变量，初始化为 <code>T</code> 类型的零值，然后返回变量地址，返回的指针类型为<code>*T</code>。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">p := <span class="built_in">new</span>(<span class="type">int</span>)   <span class="comment">// p, *int 类型, 指向匿名的 int 变量</span></span><br><span class="line">fmt.Println(*p) <span class="comment">// &quot;0&quot;</span></span><br><span class="line">*p = <span class="number">2</span>          <span class="comment">// 设置 int 匿名变量的值为 2</span></span><br><span class="line">fmt.Println(*p) <span class="comment">// &quot;2&quot;</span></span><br></pre></td></tr></table></figure>
<p><code>new</code> 函数创建变量和普通变量声明语句方式创建变量没有什么区别，除了不需要声明一个临时变量的名字外，还可以在表达式中使用 <code>new(T)</code>。其实这就是一种语法糖，而不是一个新的基础概念。<code>new</code> 函数使用通常相对比较少，因为对于结构体来说，直接用字面量语法创建新变量的方法会更灵活。由于 <code>new</code> 只是一个预定义的函数，它并不是一个关键字，因此可以将 <code>new</code> 名字重新定义为别的类型。例如下面的例子：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">delta</span><span class="params">(old, <span class="built_in">new</span> <span class="type">int</span>)</span></span> <span class="type">int</span> &#123; <span class="keyword">return</span> <span class="built_in">new</span> - old &#125;</span><br></pre></td></tr></table></figure>
<p>由于 <code>new </code>被定义为 <code>int</code> 类型的变量名，因此在 <code>delta</code> 函数内部无法使用内置的<code> new</code> 函数。</p>
<h2 id="全局变量">全局变量</h2>
<p>全局声明变量，如果没有使用不会编译报错。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">	author  <span class="type">string</span></span><br><span class="line">	address <span class="type">string</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="匿名变量">匿名变量</h2>
<p>在使用多重赋值时，如果想要忽略某个值，可以使用 <code>匿名变量（anonymous variable）</code>。 匿名变量用一个下划线<code>_</code>表示，比如：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 该函数返回两个值</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getName</span><span class="params">()</span></span> (firstName, lastName <span class="type">string</span>) &#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="string">&quot;wangpengliang&quot;</span>, <span class="string">&quot;lizimeng&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="comment">// _ 代表匿名变量,匿名变量将会被忽略</span></span><br><span class="line">	result, _ := getName()</span><br><span class="line">	fmt.Println(result)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>匿名变量不占用命名空间，不会分配内存，所以匿名变量之间不存在重复声明。 (在<code>Lua</code>等编程语言里，匿名变量也被叫做哑元变量)</p>
<p><strong>注意：</strong></p>
<ol>
<li>函数外的每个语句都必须以关键字开始（var、const、func等）</li>
<li><code>:=</code> 不能使用在函数外</li>
<li><code>_ </code>多用于占位，表示忽略值</li>
</ol>
<h2 id="变量生命周期">变量生命周期</h2>
<p>变量的生命周期指的是在程序运行期间变量有效存在的时间段。</p>
<ul>
<li>对于在包一级声明的变量来说，它们生命周期和整个程序的运行周期一致</li>
<li>在局部变量的声明周期是动态的：从每次创建一个新变量的声明语句开始，直到该变量不再被引用为止，然后变量的存储空间可能被回收</li>
<li>函数的参数变量和返回值变量都是局部变量。它们在函数每次被调用的时候创建</li>
</ul>
<p>这里需要注意一个问题，看以下代码：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> global *<span class="type">int</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">f</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">var</span> x <span class="type">int</span></span><br><span class="line">    x = <span class="number">1</span></span><br><span class="line">    global = &amp;x</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">g</span><span class="params">()</span></span> &#123;</span><br><span class="line">    y := <span class="built_in">new</span>(<span class="type">int</span>)</span><br><span class="line">    *y = <span class="number">1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><code>f()</code> 里的 <code>x</code> 变量必须在堆上分配，因为它在函数退出后依然可以通过包一级的 <code>global</code> 变量找到，虽然它是在函数内部定义的。用Go语言的术语说，这个  <code>x </code> 局部变量从函数 <code>f</code> 中逃逸了。相反，当 <code>g</code> 函数返回时，变量  <code>*y</code> 将是不可达的，也就是说可以马上被回收的。因此：<code>*y</code> 并没有从函数 <code>g</code> 中逃逸，虽然这里用的是 <code>new</code> 方式。编译器会自动选择在栈上还是在堆上分配局部变量的存储空间 而不是用 <code>var</code> 还是 <code>new</code> 声明变量的方式区分。</p>
<h2 id="变量赋值">变量赋值</h2>
<p>使用赋值语句可以更新一个变量的值，最简单的赋值语句是将要被赋值的变量放在=的左边，新值的表达式放在=的右边。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">x = <span class="number">1</span>                       <span class="comment">// 命名变量的赋值</span></span><br><span class="line">*p = <span class="literal">true</span>                   <span class="comment">// 通过指针间接赋值</span></span><br><span class="line">person.name = <span class="string">&quot;bob&quot;</span>         <span class="comment">// 结构体字段赋值</span></span><br><span class="line">count[x] = count[x] * scale <span class="comment">// 数组、slice或map的元素赋值</span></span><br></pre></td></tr></table></figure>
<p>特定的二元算术运算符和赋值语句的复合操作有一个简洁形式，例如上面最后的语句可以重写为：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">count[x] *= scale</span><br></pre></td></tr></table></figure>
<p>这样可以省去对变量表达式的重复计算。数值变量也可以支持 <code>++</code> 递增和 <code>--</code> 递减语句</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">v := <span class="number">1</span></span><br><span class="line">v++    <span class="comment">// 等价方式 v = v + 1；v 变成 2</span></span><br><span class="line">v--    <span class="comment">// 等价方式 v = v - 1；v 变成 1</span></span><br></pre></td></tr></table></figure>
<p>除此之外Go语言还支持多重赋值，在不支持多重赋值的语言中，交换两个变量的内容需要引入一个中间变量，但是Go语言中不需要，比如：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> i <span class="type">int</span> = <span class="number">10</span></span><br><span class="line"><span class="keyword">var</span> j <span class="type">int</span> = <span class="number">20</span></span><br><span class="line">i, j = j, i</span><br></pre></td></tr></table></figure>
<h1 id="包和文件">包和文件</h1>
<p>Go 语言中的包与C#中的 <code>namespace</code> 的概念类似，目的都是为了支持模块化、封装、单独编译和代码重用。每个Go文件都只能属于一个包。一个包可以由许多以 <code>.go</code> 为扩展名的源文件组成，因此文件名和包名一般来说都是不相同的。</p>
<h2 id="包初始化顺序">包初始化顺序</h2>
<p>如果包中含有多个 <code>.go</code>  源文件，将按照发给编译器的顺序进行初始化，Go语言的构建工具首先会将 <code>.go</code> 文件根据文件名排序，然后依次调用编译器编译。</p>
<h2 id="包级别变量处理">包级别变量处理</h2>
<p>对于在包级别声明的变量，如果有初始化表达式则用表达式初始化，如果存在没有初始化表达式的，可以用一个特殊的 <code>init</code> 初始化函数来简化初始化工作。每个文件可以包含多个 <code>init</code> 初始化函数。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123; &#125;</span><br></pre></td></tr></table></figure>
<p><code>init</code> 初始化函数除了不能被调用或引用外，其他行为和普通函数类似。每个文件中的 <code>init</code> 初始化函数，在程序开始执行时按照声明的顺序被自动调用。 每个包在解决依赖的前提下，以导入声明的顺序初始化，每个包只会被初始化一次。因此，如果 <code>a</code> 包 导入了 <code>b</code> 包，那么在 <code>a</code> 包初始化的时候可以认为 <code>b</code> 包必然已经初始化过了。初始化工作是自下而上进行的， <code>main</code> 包最后被初始化。这种方式可以确保在 <code>main</code> 函数执行之前所有依赖的包都已经完成初始化。</p>
<h2 id="导出包">导出包</h2>
<p>Go 语言中根据首字母的大小写来确定可以访问的权限。如果首字母大写则可以被其他的包访问；如果首字母小写，则只能在本包中使用。该规则适用于全局变量、全局常量、类型、结构字段、函数、方法等。可以简单的理解成：<em>首字母大写是公有的，首字母小写是私有的</em>。只能访问包导出的名字，未导出的名字不能被包外的代码访问。</p>
<h2 id="导入包">导入包</h2>
<p>使用包成员需要使用 <code>import</code> 关键字导入，但不能形成导入循环。</p>
<p><strong>导入系统包：</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span> </span><br></pre></td></tr></table></figure>
<p><strong>相对路径导入包：导入同一目录下 test 包</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;./test&quot;</span> </span><br></pre></td></tr></table></figure>
<p><strong>绝对路径导入包：导入 <code>gopath/src/oldboy/python</code> 包</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;oldboy/python&quot;</span></span><br></pre></td></tr></table></figure>
<p><strong>导入包并启用别名：导入<code>fmt</code>并启用别名 <code>f2</code></strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> f2 <span class="string">&quot;fmt&quot;</span></span><br></pre></td></tr></table></figure>
<p>将 <code>fmt</code> 启用别名<code>.</code>可以直接使用内容而不用再添加 <code>fmt</code> 。比如 <code>fmt.Println</code> 可以直接写成 <code>Println</code></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> . <span class="string">&quot;fmt&quot;</span> </span><br></pre></td></tr></table></figure>
<p><strong>import _</strong></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span>  _ <span class="string">&quot;fmt&quot;</span>  </span><br></pre></td></tr></table></figure>
<p>这表示只使用该包的 <code>init</code> 函数，并不使用该包的其他内容。这种形式的 <code>import</code> ，在 <code>import</code>时就执行了 <code>fmt</code> 包中的 <code>init</code> 函数。</p>
<p><strong>注意</strong>：未使用的导入包，会被编译器视为错误 (不包括 <code>&quot;import _&quot;</code>)。实例如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>编译错误：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./main.go:4:2: imported and not used: &quot;fmt&quot;</span><br></pre></td></tr></table></figure>
<h1 id="作用域">作用域</h1>
<p>一个声明语句将程序中的实体和一个名字关联，比如一个函数或一个变量。声明语句的作用域是指源代码中可以有效使用这个名字的范围。</p>
<p>作用域和生命周期不能混为一谈。声明语句的作用域对应的是一个源代码的文本区域；它是一个编译时的属性。一个变量的生命周期是指程序运行时变量存在的有效时间段，在此时间区域内它可以被程序的其他部分引用；是一个运行时的概念。</p>
<p>声明语句对应的词法域决定了作用域范围的大小。对于内置的类型、函数和常量，比如 <code>int</code>、<code>len</code>和 <code>true</code> 等是在全局作用域的，因此可以在整个程序中直接使用。任何在函数外部（也就是包级语法域）声明的名字可以在同一个包的任何源文件中访问的。对于导入的包，例如 <code>tempconv</code> 导入的 <code>fmt</code> 包，则是对应源文件级的作用域，因此只能在当前的文件中访问导入的 <code>fmt</code> 包，当前包的其它源文件无法访问在当前源文件导入的包。还有许多声明语句，比如 <code>tempconv.CToF</code> 函数中的变量 <code>c</code>，则是局部作用域的，它只能在函数内部（甚至只能是局部的某些部分）访问。</p>
<h1 id="常量">常量</h1>
<p>常量表达式的值在编译期计算，而不是在运行期。每种常量的潜在类型都是基础类型：<code>boolean</code>、<code>string</code>或数字。Go语言中常量指：编译期间就已知且不可改变的值。使用 <code>const</code> 关键字定义常量。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> PI <span class="type">float64</span> = <span class="number">3.14159265358979323846</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 显式类型定义,常量名称推荐全大写</span></span><br><span class="line"><span class="keyword">const</span> LENGTH <span class="type">int</span> = <span class="number">10</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 隐式类型定义,其实也是使用类型推导</span></span><br><span class="line"><span class="keyword">const</span> WIDTH = <span class="number">20</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 多重定义</span></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">	size <span class="type">int64</span> = <span class="number">1024</span></span><br><span class="line">	eof        = <span class="number">-1</span> <span class="comment">// 无类型整型常量</span></span><br><span class="line">)</span><br><span class="line"><span class="comment">// 或者这样</span></span><br><span class="line"><span class="keyword">const</span> a, b, c = <span class="number">1</span>, <span class="literal">false</span>, <span class="string">&quot;hello world&quot;</span> <span class="comment">// 常量的多重赋值</span></span><br></pre></td></tr></table></figure>
<h2 id="iota">iota</h2>
<p>常量声明可以使用 <code>iota</code> 常量生成器初始化，它用于生成一组以相似规则初始化的常量，但是不用每行都写一遍初始化表达式。在一个 <code>const</code> 声明语句中，在第一个声明的常量所在行的 <code>iota</code> 将会被置为 <code>0</code> ，然后在每一个有常量声明的行加 <code>1</code>。(Go语言没有枚举类型，可以使用 <code>const+iota</code> 模拟)</p>
<blockquote>
<p>关键字 <code>iota</code> 定义常量组中从0开始按行计数的自增枚举值。<code>iota</code> 在 <code>const</code> 关键字出现时将被重置为0 (const内部的第一行之前)，const中每新增一行常量声明将使 <code>iota</code> 计数一次。</p>
</blockquote>
<p>普通常量组：如果不指定类型和初始化值，则与上一行非空常量右值相同</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">   Windows = <span class="number">0</span></span><br><span class="line">   Linux</span><br><span class="line">   MaxOS</span><br><span class="line">)</span><br><span class="line">fmt.Println(Windows, Linux, MaxOS) <span class="comment">// output: 0 0 0</span></span><br></pre></td></tr></table></figure>
<p>结合 <code>iota</code> 实现枚举：第一个 <code>iota</code> 等于0，每当 <code>iota</code> 在新的一行被使用，它的值自增1</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">   Sunday    = <span class="literal">iota</span> <span class="comment">// 0</span></span><br><span class="line">   Monday           <span class="comment">// 1,通常省略后续行行表达式。</span></span><br><span class="line">   Tuesday          <span class="comment">// 2</span></span><br><span class="line">   Wednesday        <span class="comment">// 3</span></span><br><span class="line">   Thursday         <span class="comment">// 4</span></span><br><span class="line">   Friday           <span class="comment">// 5</span></span><br><span class="line">   Saturday         <span class="comment">// 6</span></span><br><span class="line">)</span><br><span class="line">fmt.Println(Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)</span><br></pre></td></tr></table></figure>
<p><code>iota</code> 插队：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">   a1 = <span class="literal">iota</span>    <span class="comment">// 0</span></span><br><span class="line">   a2           <span class="comment">// 1</span></span><br><span class="line">   b1 = <span class="string">&quot;hello&quot;</span> <span class="comment">// 独立值hello,iota+=1</span></span><br><span class="line">   b2           <span class="comment">// 如不指定类型和初始化值，则与上一行非空常量右值相同,所以是hello;iota+=1</span></span><br><span class="line">   c1 = <span class="literal">iota</span>    <span class="comment">// 恢复自增,4</span></span><br><span class="line">   c2           <span class="comment">// 5</span></span><br><span class="line">)</span><br><span class="line">fmt.Println(a1, a2, b1, b2, c1, c2) <span class="comment">// output:0 1 hello hello 4 5</span></span><br></pre></td></tr></table></figure>
<p><code>iotl</code> 忽略：使用 <code>_</code> 忽略某些值</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">	d1 = <span class="literal">iota</span></span><br><span class="line">	d2</span><br><span class="line">	_</span><br><span class="line">	d3</span><br><span class="line">)</span><br><span class="line">fmt.Println(d1, d2, d3) <span class="comment">// output:0 1 3</span></span><br></pre></td></tr></table></figure>
<p><code>iota</code> 定义数量级</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">	_  = <span class="literal">iota</span>             <span class="comment">// _表示将0忽略</span></span><br><span class="line">	KB = <span class="number">1</span> &lt;&lt; (<span class="number">10</span> * <span class="literal">iota</span>) <span class="comment">// 表示1左移十位，转换为十进制就是1024</span></span><br><span class="line">	MB = <span class="number">1</span> &lt;&lt; (<span class="number">10</span> * <span class="literal">iota</span>)</span><br><span class="line">	GB = <span class="number">1</span> &lt;&lt; (<span class="number">10</span> * <span class="literal">iota</span>)</span><br><span class="line">	TB = <span class="number">1</span> &lt;&lt; (<span class="number">10</span> * <span class="literal">iota</span>)</span><br><span class="line">	PB = <span class="number">1</span> &lt;&lt; (<span class="number">10</span> * <span class="literal">iota</span>)</span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<p>同一常量组中，可以提供多个 <code>iota</code>，它们各自增⻓。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> (</span><br><span class="line">	a, b = <span class="literal">iota</span> + <span class="number">1</span>, <span class="literal">iota</span> + <span class="number">2</span> <span class="comment">// a=iota+1 b=iota+2 =&gt; 1,2</span></span><br><span class="line">	c, d                      <span class="comment">// c=iota(1)+1 b=iota(2)+1 =&gt; 2,3</span></span><br><span class="line">)</span><br><span class="line">fmt.Println(a, b, c, d)</span><br></pre></td></tr></table></figure>

</div>


  <div class="book-comments">
    




  </div>



<script src="/js/book-post.js"></script>

        </div>
      </div>
      <div class="column col-2 hide-lg">
        <div class="book-post-info">
  
    <div class="book-post-meta">

  <div class="author">

    <!-- Author image -->
    <div class="author-img">
      
        <figure
          class="avatar avatar-lg"
          data-initial="W"
          style="background-color: #3b4351;">
        </figure>
      
    </div>

    <!-- Author title -->
    <div class="author-title">
      <div>WangPengLiang</div>
      <div>2022-03-30</div>
    </div>
  </div>

  

  <div class="divider"></div>
</div>
  

  <div class="book-tocbot">
</div>
<div class="book-tocbot-menu">
  <a class="book-toc-expand" onclick="expand_toc()">Expand all</a>
  <a onclick="go_top()">Back to top</a>
  <a onclick="go_bottom()">Go to bottom</a>
</div>


<script src="/js/book-toc.js"></script>

</div>
      </div>
    </div>
  </div>
  
  <a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>

</body>
</html>


<script src="/js/book.js"></script>
